package com.fiona.remoting.netty.client;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.fiona.core.message.Message;
import com.fiona.core.message.RpcResponse;
import com.fiona.core.message.enums.SerializationTypeEnum;
import com.fiona.remoting.api.Client;
import com.fiona.remoting.netty.Constants;

import io.netty.channel.Channel;
import io.netty.channel.ChannelFutureListener;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import io.netty.handler.timeout.IdleState;
import io.netty.handler.timeout.IdleStateEvent;
import io.netty.util.ReferenceCountUtil;

/**
 * @author huacongnan
 */
public class NettyClientHandler extends ChannelInboundHandlerAdapter {
	private Logger logger = LoggerFactory.getLogger(NettyClientHandler.class);
	NettyClient client;

    public NettyClientHandler(Client client) {
        this.client = (NettyClient) client;
    }

    /**
     * Read the message transmitted by the server
     */
    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) {
        try {
        	logger.info("client receive msg: [{}]", msg);
            if (msg instanceof Message) {
            	Message tmp = (Message) msg;
                byte messageType = tmp.getType();
                if (messageType == Constants.HEARTBEAT_RESPONSE_TYPE) {
                	logger.info("heart [{}]", tmp.getData());
                } else if (messageType == Constants.RESPONSE_TYPE) {
                    RpcResponse rpcResponse = (RpcResponse) tmp.getData();
                    client.received();
                }
            }
        } finally {
            ReferenceCountUtil.release(msg);
        }
    }

    @Override
    public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception {
        if (evt instanceof IdleStateEvent) {
            IdleState state = ((IdleStateEvent) evt).state();
            if (state == IdleState.WRITER_IDLE) {
            	logger.info("write idle happen [{}]", ctx.channel().remoteAddress());
                Channel channel = client.getNettyChannel();
                Message message = new Message();
                message.setCodec(SerializationTypeEnum.PROTOSTUFF.getCode());
                message.setType(Constants.HEARTBEAT_REQUEST_TYPE);
                message.setData(Constants.PING);
                channel.writeAndFlush(message).addListener(ChannelFutureListener.CLOSE_ON_FAILURE);
            }
        } else {
            super.userEventTriggered(ctx, evt);
        }
    }

    /**
     * Called when an exception occurs in processing a client message
     */
    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
    	logger.error("client catch exception：", cause);
        cause.printStackTrace();
        ctx.close();
    }

}

